package org.zoomdev.zoom.retry;

import java.io.Serializable;
import java.sql.*;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

/**
        * 持久化重试服务 - 支持任务状态持久化和启动恢复
        */
public class PersistentRetryService {

    // 数据库接口
    private final TaskStore taskStore;

    // 核心Timer实例
    private final DriftProofTimer timer;

    // 任务ID生成器
    private final AtomicLong taskIdGenerator = new AtomicLong(0);

    // 清理线程池
    private final ScheduledExecutorService cleanupExecutor;

    public PersistentRetryService(TaskStore taskStore) {
        this.taskStore = taskStore;
        this.timer = new DriftProofTimer();
        this.cleanupExecutor = Executors.newSingleThreadScheduledExecutor();
    }

    public PersistentRetryService(TaskStore taskStore, DriftProofTimer timer) {
        this.taskStore = taskStore;
        this.timer = timer;
        this.cleanupExecutor = Executors.newSingleThreadScheduledExecutor();
    }

    /**
            * 启动服务
     */
    public void start() {
        // 启动清理任务
        Duration retentionPeriod = taskStore.getDefaultRetentionPeriod();
        cleanupExecutor.scheduleAtFixedRate(() -> {
            try {
                System.out.println("Running task cleanup...");
                Instant cutoff = Instant.now().minus(retentionPeriod);
                int deletedCount = taskStore.deleteCompletedTasksBefore(cutoff);
                System.out.printf("Deleted %d completed tasks older than %s%n", deletedCount, cutoff);
            } catch (SQLException e) {
                System.err.println("Failed to cleanup tasks: " + e.getMessage());
            }
        }, 1, 1, TimeUnit.HOURS); // 每小时执行一次

        // 恢复未完成任务
        try {
            List<RetryTaskRecord> pendingTasks = taskStore.loadPendingTasks();
            System.out.printf("Found %d pending tasks to recover%n", pendingTasks.size());

            for (RetryTaskRecord taskRecord : pendingTasks) {
                scheduleTaskFromRecord(taskRecord);
            }
        } catch (SQLException e) {
            System.err.println("Failed to load pending tasks: " + e.getMessage());
        }

        // 启动定时器
        timer.start();
    }

    /**
            * 停止服务
     */
    public void stop() {
        // 停止清理任务
        cleanupExecutor.shutdown();

        // 停止定时器
        timer.stop();

        try {
            cleanupExecutor.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
            * 安排Job任务（一次性）
            */
    public long scheduleJob(Job job, long delay, TimeUnit unit,
                            RetryStrategy retryStrategy, Long maxRetryDuration, TimeUnit maxUnit,
                            Integer maxRetries) {
        // 创建任务记录
        RetryTaskRecord record = new RetryTaskRecord();
        record.setTaskId(taskIdGenerator.incrementAndGet());
        record.setJob(job);
        record.setDelayMillis(unit.toMillis(delay));
        record.setPeriod(-1); // 一次性任务
        record.setRetryStrategyType(retryStrategy.getType());
        record.setRetryStrategyConfig(retryStrategy.serializeConfig());
        record.setMaxRetryDuration(maxRetryDuration != null ? maxUnit.toMillis(maxRetryDuration) : -1);
        record.setMaxRetries(maxRetries);
        record.setStatus(RetryTaskStatus.PENDING);
        record.setCreatedAt(Instant.now());
        record.setNextExecutionTime(Instant.now().plusMillis(record.getDelayMillis()));

        try {
            taskStore.saveTask(record);

            // 安排任务
            scheduleTask(record);
            return record.getTaskId();
        } catch (SQLException e) {
            System.err.println("Failed to save task: " + e.getMessage());
            return -1;
        }
    }

    /**
            * 安排周期性Job任务
     */
    public long scheduleJobWithFixedDelay(Job job, long initialDelay, long period, TimeUnit unit,
                                          RetryStrategy retryStrategy, Long maxRetryDuration, TimeUnit maxUnit,
                                          Integer maxRetries) {
        // 创建任务记录
        RetryTaskRecord record = new RetryTaskRecord();
        record.setTaskId(taskIdGenerator.incrementAndGet());
        record.setJob(job);
        record.setDelayMillis(unit.toMillis(initialDelay));
        record.setPeriod(unit.toMillis(period)); // 周期性任务
        record.setRetryStrategyType(retryStrategy.getType());
        record.setRetryStrategyConfig(retryStrategy.serializeConfig());
        record.setMaxRetryDuration(maxRetryDuration != null ? maxUnit.toMillis(maxRetryDuration) : -1);
        record.setMaxRetries(maxRetries);
        record.setStatus(RetryTaskStatus.PENDING);
        record.setCreatedAt(Instant.now());
        record.setNextExecutionTime(Instant.now().plusMillis(record.getDelayMillis()));

        try {
            taskStore.saveTask(record);

            // 安排任务
            scheduleTask(record);
            return record.getTaskId();
        } catch (SQLException e) {
            System.err.println("Failed to save task: " + e.getMessage());
            return -1;
        }
    }

    /**
            * 从持久化记录安排任务
     */
    private void scheduleTaskFromRecord(RetryTaskRecord record) {
        // 创建重试策略
        RetryStrategy retryStrategy = createRetryStrategy(record);

        // 计算延迟时间
        long initialDelay = Duration.between(Instant.now(), record.getNextExecutionTime()).toMillis();
        if (initialDelay < 0) {
            initialDelay = 0; // 立即执行
        }

        // 安排任务
        Runnable taskRunner = () -> executeJobWithRetry(record.getJob(), record.getTaskId(), retryStrategy,
                record.getMaxRetryDuration(), record.getMaxRetries());

        if (record.getPeriod() > 0) {
            timer.scheduleWithFixedDelay(taskRunner, initialDelay, record.getPeriod(), TimeUnit.MILLISECONDS);
        } else {
            timer.schedule(taskRunner, initialDelay, TimeUnit.MILLISECONDS);
        }
    }

    /**
            * 安排任务
     */
    private void scheduleTask(RetryTaskRecord record) {
        // 计算延迟时间
        long initialDelay = Duration.between(Instant.now(), record.getNextExecutionTime()).toMillis();
        if (initialDelay < 0) {
            initialDelay = 0; // 立即执行
        }

        // 安排任务
        Runnable taskRunner = () -> executeJobWithRetry(record.getJob(), record.getTaskId(),
                createRetryStrategy(record),
                record.getMaxRetryDuration(), record.getMaxRetries());

        if (record.getPeriod() > 0) {
            timer.scheduleWithFixedDelay(taskRunner, initialDelay, record.getPeriod(), TimeUnit.MILLISECONDS);
        } else {
            timer.schedule(taskRunner, initialDelay, TimeUnit.MILLISECONDS);
        }
    }

    /**
            * 创建重试策略
     */
    private RetryStrategy createRetryStrategy(RetryTaskRecord record) {
        switch (record.getRetryStrategyType()) {
            case SIMPLE:
                return new SimpleRetryStrategy(record.getRetryStrategyConfig());
            case DELAY_SEQUENCE:
                return new DelaySequenceRetryStrategy(record.getRetryStrategyConfig());
            case SCHEDULED:
                return new ScheduledRetryStrategy(record.getRetryStrategyConfig());
            default:
                throw new IllegalArgumentException("Unknown retry strategy: " + record.getRetryStrategyType());
        }
    }

    /**
            * 执行Job并处理重试逻辑
     */
    private void executeJobWithRetry(Job job, long taskId,
                                     RetryStrategy retryStrategy,
                                     long maxRetryDuration, Integer maxRetries) {
        try {
            // 更新任务状态为执行中
            updateTaskStatus(taskId, RetryTaskStatus.EXECUTING, Instant.now(), null);

            // 执行任务
            job.run();

            // 任务成功
            updateTaskStatus(taskId, RetryTaskStatus.COMPLETED, Instant.now(), null);
        } catch (Exception e) {
            handleJobFailure(job, taskId, e, retryStrategy, maxRetryDuration, maxRetries);
        }
    }

    /**
            * 处理Job失败情况
     */
    private void handleJobFailure(Job job, long taskId, Exception e,
                                  RetryStrategy retryStrategy,
                                  long maxRetryDuration, Integer maxRetries) {
        try {
            // 从数据库加载任务状态
            RetryTaskRecord record = taskStore.getTask(taskId);
            if (record == null) {
                System.err.printf("Task %d not found in database%n", taskId);
                return;
            }

            // 记录第一次失败时间
            if (record.getFirstFailureTime() == null) {
                record.setFirstFailureTime(Instant.now());
                taskStore.updateTask(record);
            }

            // 检查是否超过最大重试次数
            if (maxRetries != null && record.getRetryCount() >= maxRetries) {
                System.out.printf("Task %d exceeded max retries (%d). Stopping retries.%n",
                        taskId, maxRetries);
                updateTaskStatus(taskId, RetryTaskStatus.FAILED, Instant.now(), "Max retries exceeded");
                return;
            }

            // 检查是否超过最大重试时间
            if (maxRetryDuration > 0 &&
                    Duration.between(record.getFirstFailureTime(), Instant.now()).toMillis() > maxRetryDuration) {
                System.out.printf("Task %d exceeded max retry duration (%dms). Stopping retries.%n",
                        taskId, maxRetryDuration);
                updateTaskStatus(taskId, RetryTaskStatus.FAILED, Instant.now(), "Max retry duration exceeded");
                return;
            }

            // 计算下次重试延迟
            long nextDelay = retryStrategy.calculateNextDelay(record.getRetryCount());
            if (nextDelay < 0) {
                System.out.printf("Task %d has no more retry attempts. Stopping retries.%n", taskId);
                updateTaskStatus(taskId, RetryTaskStatus.FAILED, Instant.now(), "No more retry attempts");
                return;
            }

            // 更新重试计数
            record.setRetryCount(record.getRetryCount() + 1);
            record.setNextExecutionTime(Instant.now().plusMillis(nextDelay));
            record.setStatus(RetryTaskStatus.RETRY_SCHEDULED);
            taskStore.updateTask(record);

            System.out.printf("Scheduling retry #%d for task %d at %s%n",
                    record.getRetryCount(), taskId, record.getNextExecutionTime());

            // 使用Timer调度重试
            timer.schedule(() -> executeJobWithRetry(job, taskId, retryStrategy, maxRetryDuration, maxRetries),
                    nextDelay, TimeUnit.MILLISECONDS);
        } catch (SQLException ex) {
            System.err.printf("Failed to handle failure for task %d: %s%n", taskId, ex.getMessage());
        }
    }

    /**
            * 更新任务状态
     */
    private void updateTaskStatus(long taskId, RetryTaskStatus status, Instant updatedAt, String failureReason) {
        try {
            RetryTaskRecord record = taskStore.getTask(taskId);
            if (record != null) {
                record.setStatus(status);
                record.setUpdatedAt(updatedAt);
                if (failureReason != null) {
                    record.setFailureReason(failureReason);
                }
                taskStore.updateTask(record);
            }
        } catch (SQLException e) {
            System.err.printf("Failed to update status for task %d: %s%n", taskId, e.getMessage());
        }
    }

    /**
            * 获取底层Timer实例
     */
    public DriftProofTimer getTimer() {
        return timer;
    }

    /**
            * 任务状态枚举
     */
    public enum RetryTaskStatus {
        PENDING,          // 任务已创建但尚未执行
        EXECUTING,        // 任务正在执行
        RETRY_SCHEDULED,  // 任务执行失败，已安排重试
        COMPLETED,        // 任务成功完成
        FAILED,           // 任务失败且不再重试
        ABORTED           // 任务被取消
    }

    /**
            * 任务持久化记录
     */
    public static class RetryTaskRecord implements Serializable {
        private long taskId;
        private Job job;
        private long delayMillis;
        private long period; // -1 表示非周期性任务
        private RetryStrategyType retryStrategyType;
        private String retryStrategyConfig;
        private long maxRetryDuration; // 最大重试时间(ms)
        private Integer maxRetries;     // 最大重试次数
        private Instant firstFailureTime;
        private int retryCount;
        private RetryTaskStatus status;
        private Instant nextExecutionTime;
        private Instant createdAt;
        private Instant updatedAt;
        private String failureReason;

        public long getTaskId() {
            return taskId;
        }

        public void setTaskId(long taskId) {
            this.taskId = taskId;
        }

        public Job getJob() {
            return job;
        }

        public void setJob(Job job) {
            this.job = job;
        }

        public long getDelayMillis() {
            return delayMillis;
        }

        public void setDelayMillis(long delayMillis) {
            this.delayMillis = delayMillis;
        }

        public long getPeriod() {
            return period;
        }

        public void setPeriod(long period) {
            this.period = period;
        }

        public RetryStrategyType getRetryStrategyType() {
            return retryStrategyType;
        }

        public void setRetryStrategyType(RetryStrategyType retryStrategyType) {
            this.retryStrategyType = retryStrategyType;
        }

        public String getRetryStrategyConfig() {
            return retryStrategyConfig;
        }

        public void setRetryStrategyConfig(String retryStrategyConfig) {
            this.retryStrategyConfig = retryStrategyConfig;
        }

        public long getMaxRetryDuration() {
            return maxRetryDuration;
        }

        public void setMaxRetryDuration(long maxRetryDuration) {
            this.maxRetryDuration = maxRetryDuration;
        }

        public Integer getMaxRetries() {
            return maxRetries;
        }

        public void setMaxRetries(Integer maxRetries) {
            this.maxRetries = maxRetries;
        }

        public Instant getFirstFailureTime() {
            return firstFailureTime;
        }

        public void setFirstFailureTime(Instant firstFailureTime) {
            this.firstFailureTime = firstFailureTime;
        }

        public int getRetryCount() {
            return retryCount;
        }

        public void setRetryCount(int retryCount) {
            this.retryCount = retryCount;
        }

        public RetryTaskStatus getStatus() {
            return status;
        }

        public void setStatus(RetryTaskStatus status) {
            this.status = status;
        }

        public Instant getNextExecutionTime() {
            return nextExecutionTime;
        }

        public void setNextExecutionTime(Instant nextExecutionTime) {
            this.nextExecutionTime = nextExecutionTime;
        }

        public Instant getCreatedAt() {
            return createdAt;
        }

        public void setCreatedAt(Instant createdAt) {
            this.createdAt = createdAt;
        }

        public Instant getUpdatedAt() {
            return updatedAt;
        }

        public void setUpdatedAt(Instant updatedAt) {
            this.updatedAt = updatedAt;
        }

        public String getFailureReason() {
            return failureReason;
        }

        public void setFailureReason(String failureReason) {
            this.failureReason = failureReason;
        }

        // getters/setters
        // ...
    }

    /**
            * 任务存储接口
     */
    public interface TaskStore {
        /** 获取默认保留期限 */
        default Duration getDefaultRetentionPeriod() {
            return Duration.ofDays(90); // 默认为90天
        }

        /** 保存任务 */
        void saveTask(RetryTaskRecord task) throws SQLException;

        /** 更新任务 */
        void updateTask(RetryTaskRecord task) throws SQLException;

        /** 获取任务 */
        RetryTaskRecord getTask(long taskId) throws SQLException;

        /** 加载所有待处理任务 */
        List<RetryTaskRecord> loadPendingTasks() throws SQLException;

        /** 删除在指定时间前完成的任务 */
        int deleteCompletedTasksBefore(Instant cutoff) throws SQLException;
    }

    /**
            * H2任务存储实现
     */
    public static class H2TaskStore implements TaskStore {
        private final Connection connection;

        public H2TaskStore(String dbUrl) throws SQLException {
            this.connection = DriverManager.getConnection(dbUrl);
            initializeDatabase();
        }

        private void initializeDatabase() throws SQLException {
            try (Statement stmt = connection.createStatement()) {
                String createTableSQL = "CREATE TABLE IF NOT EXISTS retry_tasks ("
                        + "task_id BIGINT PRIMARY KEY,"
                        + "job BLOB,"
                        + "delay_millis BIGINT,"
                        + "period BIGINT,"
                        + "retry_strategy_type VARCHAR(20),"
                        + "retry_strategy_config VARCHAR(255),"
                        + "max_retry_duration BIGINT,"
                        + "max_retries INT,"
                        + "first_failure_time TIMESTAMP,"
                        + "retry_count INT,"
                        + "status VARCHAR(20),"
                        + "next_execution_time TIMESTAMP,"
                        + "created_at TIMESTAMP,"
                        + "updated_at TIMESTAMP,"
                        + "failure_reason VARCHAR(255))";
                stmt.executeUpdate(createTableSQL);

                // 创建索引
                stmt.executeUpdate("CREATE INDEX IF NOT EXISTS idx_status ON retry_tasks(status)");
                stmt.executeUpdate("CREATE INDEX IF NOT EXISTS idx_next_exec ON retry_tasks(next_execution_time)");
            }
        }

        @Override
        public void saveTask(RetryTaskRecord task) throws SQLException {
            String sql = "INSERT INTO retry_tasks (task_id, job, delay_millis, period, retry_strategy_type, "
                    + "retry_strategy_config, max_retry_duration, max_retries, status, next_execution_time, "
                    + "created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

            try (PreparedStatement stmt = connection.prepareStatement(sql)) {
                stmt.setLong(1, task.getTaskId());
                stmt.setObject(2, serializeJob(task.getJob()));
                stmt.setLong(3, task.getDelayMillis());
                stmt.setLong(4, task.getPeriod());
                stmt.setString(5, task.getRetryStrategyType().name());
                stmt.setString(6, task.getRetryStrategyConfig());
                stmt.setLong(7, task.getMaxRetryDuration());
                stmt.setObject(8, task.getMaxRetries());
                stmt.setString(9, task.getStatus().name());
                stmt.setTimestamp(10, Timestamp.from(task.getNextExecutionTime()));
                stmt.setTimestamp(11, Timestamp.from(task.getCreatedAt()));
                stmt.setTimestamp(12, Timestamp.from(task.getCreatedAt()));

                stmt.executeUpdate();
            }
        }

        @Override
        public void updateTask(RetryTaskRecord task) throws SQLException {
            String sql = "UPDATE retry_tasks SET "
                    + "delay_millis = ?, "
                    + "period = ?, "
                    + "retry_strategy_type = ?, "
                    + "retry_strategy_config = ?, "
                    + "max_retry_duration = ?, "
                    + "max_retries = ?, "
                    + "first_failure_time = ?, "
                    + "retry_count = ?, "
                    + "status = ?, "
                    + "next_execution_time = ?, "
                    + "updated_at = ?, "
                    + "failure_reason = ? "
                    + "WHERE task_id = ?";

            try (PreparedStatement stmt = connection.prepareStatement(sql)) {
                stmt.setLong(1, task.getDelayMillis());
                stmt.setLong(2, task.getPeriod());
                stmt.setString(3, task.getRetryStrategyType().name());
                stmt.setString(4, task.getRetryStrategyConfig());
                stmt.setLong(5, task.getMaxRetryDuration());
                stmt.setObject(6, task.getMaxRetries());
                stmt.setTimestamp(7, task.getFirstFailureTime() != null ?
                        Timestamp.from(task.getFirstFailureTime()) : null);
                stmt.setInt(8, task.getRetryCount());
                stmt.setString(9, task.getStatus().name());
                stmt.setTimestamp(10, Timestamp.from(task.getNextExecutionTime()));
                stmt.setTimestamp(11, Timestamp.from(Instant.now()));
                stmt.setString(12, task.getFailureReason());
                stmt.setLong(13, task.getTaskId());

                stmt.executeUpdate();
            }
        }

        @Override
        public RetryTaskRecord getTask(long taskId) throws SQLException {
            String sql = "SELECT * FROM retry_tasks WHERE task_id = ?";
            try (PreparedStatement stmt = connection.prepareStatement(sql)) {
                stmt.setLong(1, taskId);
                try (ResultSet rs = stmt.executeQuery()) {
                    if (rs.next()) {
                        return mapRecord(rs);
                    }
                }
            }
            return null;
        }

        @Override
        public List<RetryTaskRecord> loadPendingTasks() throws SQLException {
            List<RetryTaskRecord> tasks = new ArrayList<>();
            String sql = "SELECT * FROM retry_tasks WHERE status IN (?, ?, ?)";
            try (PreparedStatement stmt = connection.prepareStatement(sql)) {
                stmt.setString(1, RetryTaskStatus.PENDING.name());
                stmt.setString(2, RetryTaskStatus.RETRY_SCHEDULED.name());
                stmt.setString(3, RetryTaskStatus.EXECUTING.name());

                try (ResultSet rs = stmt.executeQuery()) {
                    while (rs.next()) {
                        tasks.add(mapRecord(rs));
                    }
                }
            }
            return tasks;
        }

        @Override
        public int deleteCompletedTasksBefore(Instant cutoff) throws SQLException {
            String sql = "DELETE FROM retry_tasks WHERE status IN (?, ?, ?) AND created_at < ?";
            try (PreparedStatement stmt = connection.prepareStatement(sql)) {
                stmt.setString(1, RetryTaskStatus.COMPLETED.name());
                stmt.setString(2, RetryTaskStatus.FAILED.name());
                stmt.setString(3, RetryTaskStatus.ABORTED.name());
                stmt.setTimestamp(4, Timestamp.from(cutoff));

                return stmt.executeUpdate();
            }
        }

        private RetryTaskRecord mapRecord(ResultSet rs) throws SQLException {
            RetryTaskRecord record = new RetryTaskRecord();
            record.setTaskId(rs.getLong("task_id"));
            record.setJob(deserializeJob(rs.getBlob("job")));
            record.setDelayMillis(rs.getLong("delay_millis"));
            record.setPeriod(rs.getLong("period"));
            record.setRetryStrategyType(RetryStrategyType.valueOf(rs.getString("retry_strategy_type")));
            record.setRetryStrategyConfig(rs.getString("retry_strategy_config"));
            record.setMaxRetryDuration(rs.getLong("max_retry_duration"));
            record.setMaxRetries((Integer)rs.getObject("max_retries"));
            Timestamp failureTs = rs.getTimestamp("first_failure_time");
            if (failureTs != null) record.setFirstFailureTime(failureTs.toInstant());
            record.setRetryCount(rs.getInt("retry_count"));
            record.setStatus(RetryTaskStatus.valueOf(rs.getString("status")));
            record.setNextExecutionTime(rs.getTimestamp("next_execution_time").toInstant());
            record.setCreatedAt(rs.getTimestamp("created_at").toInstant());
            record.setUpdatedAt(rs.getTimestamp("updated_at").toInstant());
            record.setFailureReason(rs.getString("failure_reason"));
            return record;
        }

        private Blob serializeJob(Job job) throws SQLException {
            // 使用Java序列化 - 实际应用中可用JSON或protobuf等更灵活格式
            return connection.createBlob();
        }

        private Job deserializeJob(Blob blob) {
            // 反序列化逻辑
            return null;
        }
    }

    /**
            * Job类（需要可序列化）
            */
    public static class Job implements Serializable {
        private int retryCount;
        private Object data;
        private Object target;
        private Invoker invoker;

        public Job(Invoker invoker, Object target, Object data) {
            this.invoker = invoker;
            this.target = target;
            this.data = data;
        }

        public void run() {
            invoker.invoke(target, data, retryCount);
        }

        // getters/setters
        // ...
    }

    /**
            * 调用器接口
     */
    @FunctionalInterface
    public interface Invoker extends Serializable {
        void invoke(Object target, Object data, int retryCount);
    }

    /**
            * 重试策略类型枚举
     */
    public enum RetryStrategyType {
        SIMPLE, DELAY_SEQUENCE, SCHEDULED
    }

    /**
            * 重试策略接口
     */
    public interface RetryStrategy {
        RetryStrategyType getType();
        String serializeConfig();
        long calculateNextDelay(int currentRetry);
    }

    /**
            * 简单重试策略（固定延迟）
            */
    public static class SimpleRetryStrategy implements RetryStrategy {
        private final long fixedDelay; // 固定延迟(ms)

        public SimpleRetryStrategy(long delay, TimeUnit unit) {
            this.fixedDelay = unit.toMillis(delay);
        }

        // 从配置反序列化
        public SimpleRetryStrategy(String config) {
            this.fixedDelay = Long.parseLong(config);
        }

        @Override
        public RetryStrategyType getType() {
            return RetryStrategyType.SIMPLE;
        }

        @Override
        public String serializeConfig() {
            return String.valueOf(fixedDelay);
        }

        @Override
        public long calculateNextDelay(int currentRetry) {
            return fixedDelay;
        }
    }

    /**
            * 延时序列重试策略
     */
    public static class DelaySequenceRetryStrategy implements RetryStrategy {
        private final long[] delays; // 延迟序列(ms)

        public DelaySequenceRetryStrategy(long[] delays, TimeUnit unit) {
            this.delays = new long[delays.length];
            for (int i = 0; i < delays.length; i++) {
                this.delays[i] = unit.toMillis(delays[i]);
            }
        }

        // 从配置反序列化
        public DelaySequenceRetryStrategy(String config) {
            String[] parts = config.split(",");
            this.delays = new long[parts.length];
            for (int i = 0; i < parts.length; i++) {
                this.delays[i] = Long.parseLong(parts[i]);
            }
        }

        @Override
        public RetryStrategyType getType() {
            return RetryStrategyType.DELAY_SEQUENCE;
        }

        @Override
        public String serializeConfig() {
            StringBuilder sb = new StringBuilder();
            for (long delay : delays) {
                if (sb.length() > 0) sb.append(",");
                sb.append(delay);
            }
            return sb.toString();
        }

        @Override
        public long calculateNextDelay(int currentRetry) {
            if (currentRetry >= delays.length) {
                return -1; // 超出序列长度
            }
            return delays[currentRetry];
        }
    }

    /**
            * 定时重试策略（固定间隔）
            */
    public static class ScheduledRetryStrategy implements RetryStrategy {
        private final long fixedInterval; // 固定间隔(ms)

        public ScheduledRetryStrategy(long interval, TimeUnit unit) {
            this.fixedInterval = unit.toMillis(interval);
        }

        // 从配置反序列化
        public ScheduledRetryStrategy(String config) {
            this.fixedInterval = Long.parseLong(config);
        }

        @Override
        public RetryStrategyType getType() {
            return RetryStrategyType.SCHEDULED;
        }

        @Override
        public String serializeConfig() {
            return String.valueOf(fixedInterval);
        }

        @Override
        public long calculateNextDelay(int currentRetry) {
            return fixedInterval;
        }
    }

    /**
            * 使用示例
     */
    public static void main(String[] args) {
        try {
            // 初始化H2数据库
            Class.forName("org.h2.Driver");
            TaskStore taskStore = new H2TaskStore("jdbc:h2:mem:retrydb;DB_CLOSE_DELAY=-1");

            // 创建重试服务
            PersistentRetryService service = new PersistentRetryService(taskStore);

            // 模拟系统启动
            service.start();

            // 创建调用器
            Invoker invoker = (target, data, retryCount) -> {
                System.out.printf("[%s] Executing job on %s with %s (retry #%d)%n",
                        Instant.now(), target, data, retryCount);

                // 模拟50%失败率
                if (Math.random() < 0.5 && retryCount < 3) {
                    throw new RuntimeException("Simulated failure");
                }
            };

            // 创建Job
            Job job = new Job(invoker, "InventoryService", "StockUpdate");

            // 安排带重试的Job任务
            service.scheduleJob(job, 2, TimeUnit.SECONDS,
                    new SimpleRetryStrategy(1, TimeUnit.SECONDS),
                    10L, TimeUnit.SECONDS, // 最大重试时间10秒
                    5); // 最大重试次数5次

            // 模拟运行一段时间
            Thread.sleep(15000);

            System.out.println("Simulating system restart...");

            // 停止服务（模拟系统关闭）
            service.stop();

            // 重新创建服务（模拟系统启动）
            service = new PersistentRetryService(taskStore);
            service.start();

            // 继续运行一段时间
            Thread.sleep(10000);

            // 正常关闭
            service.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}